#include "light_emitting_material.h"
#include "scene.h"
namespace gemren
{

	err_t light_emitting_material::set_string(std::string& name, const std::string& value)
	{
		if(name=="intensity")
		{
			display_color = spectrum_dynamic(value, 0, spectrum::infinity);
			color.copy_from_spectrum(display_color);
			return ERR_OK;
		}
		return bsdf_material::set_string(name, value);
	}
	void light_emitting_material::announce_properties(const std::string& prefix, property_announcer announcer)
	{
		bsdf_material::announce_properties(prefix, announcer);
		announcer((prefix+".intensity").c_str(), ANNOUNCED_STRING, val_to_str(display_color).c_str());
	}
	/*void light_emitting_material::interact(random* ran, const Scene* scene, intersection* i)
	{
		material::interact(ran,scene,i);
	}*/
	void light_emitting_material::direct_lighting(random* ran, const scene* sc, intersection* i)
	{
		float incos = -embree::dot(i->incoming, i->triptr->normal);
		if( incos>0)	
		{// add light emitted by hit triangle

			unsigned int lm = i->lighting_mode;
			float importance= 0.0f;
			switch(i->rayorigin)
			{
			case ro_camera: 
				importance = 1.0f;
				break;
			case ro_transmitted_diffuse: //we hit this light through series of transmitters ie this is BRDF sampled caustic
				switch(lm & LM_CAUSTIC)
				{
				case LM_CAUSTIC_LIGHTSOURCE:
					importance = 0.0f;
					break;
				case LM_CAUSTIC_BRDF:
					importance = 1.0f;
					break;
				case LM_CAUSTIC_MIS:
					importance = i->mis_brdf_importance; // which was precomputed when ray first hit transmitter 
					
					break;
				}
				break;
			case ro_diffuse:
				switch(lm & LM_PRIMARY)
				{
				case LM_PRIMARY_LIGHTSOURCE:
					importance = 0.0f;
					break;
				case LM_PRIMARY_BRDF:
					importance = 1.0f;
					break;
				case LM_PRIMARY_MIS:
					//mis_brdf_importance is NOT predivided by dist*dist - that only happens at transmitter surface
					importance = sc->light_selection_probability(this)*i->t*i->t/(my_triangles.size()* incos* i->triptr->area(sc));
					importance = i->mis_brdf_importance/ (i->mis_brdf_importance + importance);
					break;
				}
				break;

			default: 
				importance = 1.0f;
				break;
			}
			i->add_light(color * importance);
		}
		bsdf_material::direct_lighting(ran, sc, i);
	}
	void light_emitting_material::enlighten_spot(const scene* sc, random* ran, intersection* i, float factor)
	{
		size_t tri_ind = ran->get()%my_triangles.size();
		const triangle& tri = sc->get_triangle(my_triangles[tri_ind]);
		
		coord2d samcoord = ran->uniform_triangle();
		const coord& v0 = sc->get_vertex(tri.v0);
		coord emitting_dir = (v0 + (sc->get_vertex(tri.v1) - v0)*samcoord.x + (sc->get_vertex(tri.v2) - v0)*samcoord.y-i->abs_pos);
		float dist = embree::length(emitting_dir);
		emitting_dir /= dist;
		float coslo = -embree::dot(emitting_dir, tri.normal);
		if(coslo<0) return; //from outside
		
		color_s mat_throughput = i->triptr->insidemat->throughput(emitting_dir, -i->incoming, i->normal);
	
		
		float pdf = dist*dist/(coslo*factor*tri.area(sc)*my_triangles.size()*factor); //probability of choosing this light direction sample
		float mis_factor = 1.0f;
		if(mat_throughput.max() > 0.0f)
		{
			
			if(!sc->point_occluded(i->abs_pos, emitting_dir, EPSILON, dist-EPSILON))
			{
				if(i->lighting_mode & LM_PRIMARY_MIS)
				{
					mis_factor = pdf/(pdf + i->triptr->insidemat->pdf(-i->incoming, emitting_dir, i->normal));
				} 
				
				i->add_light( 
					mat_throughput * 
					color * //light intensity
					( //scalars
						mis_factor/pdf
					)
				);
			}
		}
		
	}

}